package com.example.financechain.service.Impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.example.financechain.Utils.GatewayUtilss;
import com.example.financechain.Utils.JsonData;
import com.example.financechain.Utils.UUIDUtils;
import com.example.financechain.Utils.UserThreadLocal;
import com.example.financechain.config.CacheKeyManager;
import com.example.financechain.domain.DTO.TransferDTO;
import com.example.financechain.domain.entity.Role;
import com.example.financechain.domain.entity.Transfer;
import com.example.financechain.mapper.TransferMapper;
import com.example.financechain.service.IRoleService;
import com.example.financechain.service.ITransferService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.hyperledger.fabric.gateway.Contract;
import org.hyperledger.fabric.gateway.Gateway;
import org.hyperledger.fabric.gateway.Network;
import org.hyperledger.fabric.gateway.Transaction;
import org.hyperledger.fabric.sdk.Peer;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.xml.ws.soap.Addressing;
import java.time.LocalDateTime;
import java.util.EnumSet;
import java.util.UUID;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author yy
 * @since 2023-04-23
 */
@Slf4j
@Service
public class TransferServiceImpl extends ServiceImpl<TransferMapper, Transfer> implements ITransferService {



    @Autowired
    GatewayUtilss gatewayUtilss;

    @Autowired
    private IRoleService iRoleService;

    @Override
    public JsonData transferfinance(TransferDTO transferDTO) {

        Role from = getonerole(transferDTO.getFrom());

        Role to = getonerole(transferDTO.getTo());

        if (from.getRoleAccount() < transferDTO.getAmount()){
            return JsonData.buildError("您的余额不足无法转账");
        }

        Transfer transferOrder;
        synchronized (UserThreadLocal.get().getNickName().intern()){
            ITransferService transferService = (ITransferService) AopContext.currentProxy();
            transferOrder = transferService.createTransferOrder(from, to, transferDTO);
        }

        if (transferOrder!=null){
            String txid = updatetransfertxid(transferOrder, from);
            transferOrder.setTransferTxid(txid);
            return  JsonData.buildSuccess(transferOrder,"转账成功");
        }else {
            throw new RuntimeException();
        }



    }

    //@Async("taskExecutor")
    public String updatetransfertxid(Transfer transferOrder,Role from) {
        try (Gateway gateway = gatewayUtilss.build(from).connect()) {
            // Get the network and chaincode
            Network network = gateway.getNetwork("energycarchannel");
            Contract contract = network.getContract("transferfinance");

            // Set endorsement policy
            EnumSet<Peer.PeerRole> roles = EnumSet.of(Peer.PeerRole.ENDORSING_PEER);
            // ...

            // Submit transaction
            Transaction transaction = contract.createTransaction("Transfer")
                    .setEndorsingPeers(network.getChannel().getPeers(EnumSet.of(Peer.PeerRole.ENDORSING_PEER)));
            transaction.submit(transferOrder.getTransferFrom(), transferOrder.getTransferTo(), transferOrder.getAmount().toString());

            // Wait for transaction to complete and print transaction ID
            String txid = transaction.getTransactionId();
            log.info("txId:" + txid);

            UpdateWrapper<Transfer> updateWrapper =new UpdateWrapper<>();
            updateWrapper.lambda().eq(Transfer::getTransferId,transferOrder.getTransferId()).set(Transfer::getTransferTxid,txid);
            update(updateWrapper);

            return txid;

        } catch (Exception e) {
            // Handle exceptions
            e.printStackTrace();

        }

        return null;
    }

    @Override
    @Transactional
    public Transfer createTransferOrder(Role from,Role to,TransferDTO transferDTO) {

        long f = from.getRoleAccount()-transferDTO.getAmount();
        from.setRoleAccount(f);
        long t = to.getRoleAccount()+transferDTO.getAmount();
        to.setRoleAccount(t);

        UpdateWrapper<Role> updateWrapper =new UpdateWrapper<>();
        updateWrapper.lambda().eq(Role::getRoleId,from.getRoleId());
        iRoleService.update(from,updateWrapper);
//
        UpdateWrapper<Role> updateWrapper1 =new UpdateWrapper<>();
        updateWrapper1.lambda().eq(Role::getRoleId,to.getRoleId());
        iRoleService.update(to,updateWrapper1);

        //iRoleService.update().setEntity(to);

        Transfer transfer =new Transfer();
        transfer.setTransferFrom(from.getRoleName());
        transfer.setTransferTo(to.getRoleName());
        transfer.setTransferNum(transferDTO.getOrdernum());
        transfer.setAmount(transferDTO.getAmount());

        transfer.setTransferordernum(CacheKeyManager.TR+ UUIDUtils.getUUID(24));

        save(transfer);

        return transfer;

    }


    public Role getonerole(String rolename){
        LambdaQueryWrapper<Role> lambdaQueryWrapper =new LambdaQueryWrapper<>();

        lambdaQueryWrapper.eq(Role::getRoleName,rolename);

        Role one = iRoleService.getOne(lambdaQueryWrapper);

        return  one;
    }




}
